using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Linq.Expressions;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Microsoft.EntityFrameworkCore.Storage;

namespace Microsoft.EntityFrameworkCore.Dm.Storage.Internal;

public class DmTypeMappingSource : RelationalTypeMappingSource
{
	private readonly DmByteArrayTypeMapping _rowversion = new DmByteArrayTypeMapping("BINARY(8)", DbType.Binary, 8, fixedLength: false, (ValueComparer)(object)new ValueComparer<byte[]>((Expression<Func<byte[], byte[], bool>>)((byte[] v1, byte[] v2) => StructuralComparisons.StructuralEqualityComparer.Equals(v1, v2)), (Expression<Func<byte[], int>>)((byte[] v) => StructuralComparisons.StructuralEqualityComparer.GetHashCode(v)), (Expression<Func<byte[], byte[]>>)((byte[] v) => (v == null) ? null : v.ToArray())), (StoreTypePostfix)0);

	private readonly IntTypeMapping _int = new IntTypeMapping("INT", (DbType?)DbType.Int32);

	private readonly LongTypeMapping _long = new LongTypeMapping("BIGINT", (DbType?)DbType.Int64);

	private readonly ShortTypeMapping _short = new ShortTypeMapping("SMALLINT", (DbType?)DbType.Int16);

	private readonly ByteTypeMapping _byte = (ByteTypeMapping)(object)new DmByteTypeMapping("TINYINT", DbType.Byte);

	private readonly SByteTypeMapping _sByte = (SByteTypeMapping)(object)new DmSByteTypeMapping("TINYINT", DbType.SByte);

	private readonly BoolTypeMapping _bool = (BoolTypeMapping)(object)new DmBoolTypeMapping("BIT", DbType.Boolean);

	private readonly DmStringTypeMapping _fixedLengthUnicodeString = new DmStringTypeMapping("NCHAR", DbType.String, unicode: true, null, fixedLength: true);

	private readonly DmStringTypeMapping _variableLengthUnicodeString = new DmStringTypeMapping("NVARCHAR", null, unicode: true);

	private readonly DmStringTypeMapping _fixedLengthAnsiString = new DmStringTypeMapping("CHAR", DbType.AnsiString, unicode: false, null, fixedLength: true);

	private readonly DmStringTypeMapping _variableLengthAnsiString = new DmStringTypeMapping("VARCHAR", DbType.AnsiString);

	private readonly DmStringTypeMapping _textAnsiString = new DmStringTypeMapping("text", DbType.AnsiString);

	private readonly DmByteArrayTypeMapping _blobBinary = new DmByteArrayTypeMapping("blob", DbType.Binary);

	private readonly DmByteArrayTypeMapping _variableLengthBinary = new DmByteArrayTypeMapping("VARBINARY", DbType.Binary);

	private readonly DmByteArrayTypeMapping _fixedLengthBinary = new DmByteArrayTypeMapping("BINARY", DbType.Binary, null, fixedLength: true);

	private readonly DmDateTimeTypeMapping _date = new DmDateTimeTypeMapping("DATE", DbType.Date);

	private readonly DmDateTimeTypeMapping _datetime = new DmDateTimeTypeMapping("TIMESTAMP", DbType.DateTime);

	private readonly DmDateTimeTypeMapping _datetime2 = new DmDateTimeTypeMapping("TIMESTAMP", DbType.DateTime2);

	private readonly DoubleTypeMapping _double = (DoubleTypeMapping)(object)new DmDoubleTypeMapping("FLOAT", DbType.Double);

	private readonly DmDateTimeOffsetTypeMapping _datetimeoffset = new DmDateTimeOffsetTypeMapping("DATETIME WITH TIME ZONE", DbType.DateTimeOffset);

	private readonly DmDateTimeOffsetTypeMapping _datetimeoffset3 = new DmDateTimeOffsetTypeMapping("DATETIME(3) WITH TIME ZONE", DbType.DateTimeOffset);

	private readonly FloatTypeMapping _real = (FloatTypeMapping)(object)new DmFloatTypeMapping("REAL", DbType.Single);

	private readonly GuidTypeMapping _guid = new GuidTypeMapping("CHAR(36)", (DbType?)DbType.Guid);

	private readonly DecimalTypeMapping _decimal = (DecimalTypeMapping)(object)new DmDecimalTypeMapping("DECIMAL(29, 4)", DbType.Decimal, 29, 4);

	private readonly TimeSpanTypeMapping _intervaldt = (TimeSpanTypeMapping)(object)new DmTimeSpanTypeMapping("INTERVAL DAY TO SECOND");

	private readonly DmStringTypeMapping _xml = new DmStringTypeMapping("VARCHAR(8188)", DbType.String);

	private readonly Dictionary<string, RelationalTypeMapping> _storeTypeMappings;

	private readonly Dictionary<Type, RelationalTypeMapping> _clrTypeMappings;

	private readonly HashSet<string> _disallowedMappings;

	public DmTypeMappingSource([NotNull] TypeMappingSourceDependencies dependencies, [NotNull] RelationalTypeMappingSourceDependencies relationalDependencies)
		: base(dependencies, relationalDependencies)
	{
		//IL_016e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0178: Expected O, but got Unknown
		//IL_0185: Unknown result type (might be due to invalid IL or missing references)
		//IL_018f: Expected O, but got Unknown
		//IL_019c: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a6: Expected O, but got Unknown
		//IL_03e9: Unknown result type (might be due to invalid IL or missing references)
		//IL_03f3: Expected O, but got Unknown
		_storeTypeMappings = new Dictionary<string, RelationalTypeMapping>(StringComparer.OrdinalIgnoreCase)
		{
			{
				"bigint",
				(RelationalTypeMapping)(object)_long
			},
			{
				"binary varying",
				(RelationalTypeMapping)(object)_variableLengthBinary
			},
			{
				"binary",
				(RelationalTypeMapping)(object)_fixedLengthBinary
			},
			{
				"bit",
				(RelationalTypeMapping)(object)_bool
			},
			{
				"char varying",
				(RelationalTypeMapping)(object)_variableLengthAnsiString
			},
			{
				"char",
				(RelationalTypeMapping)(object)_fixedLengthAnsiString
			},
			{
				"character varying",
				(RelationalTypeMapping)(object)_variableLengthAnsiString
			},
			{
				"character",
				(RelationalTypeMapping)(object)_fixedLengthAnsiString
			},
			{
				"date",
				(RelationalTypeMapping)(object)_date
			},
			{
				"datetime",
				(RelationalTypeMapping)(object)_datetime
			},
			{
				"datetime2",
				(RelationalTypeMapping)(object)_datetime2
			},
			{
				"datetime with time zone",
				(RelationalTypeMapping)(object)_datetimeoffset
			},
			{
				"timestamp with time zone",
				(RelationalTypeMapping)(object)_datetimeoffset
			},
			{
				"datetime(3) with time zone",
				(RelationalTypeMapping)(object)_datetimeoffset3
			},
			{
				"timestamp(3) with time zone",
				(RelationalTypeMapping)(object)_datetimeoffset3
			},
			{
				"dec",
				(RelationalTypeMapping)(object)_decimal
			},
			{
				"decimal",
				(RelationalTypeMapping)(object)_decimal
			},
			{
				"float",
				(RelationalTypeMapping)(object)_double
			},
			{
				"double",
				(RelationalTypeMapping)(object)_double
			},
			{
				"image",
				(RelationalTypeMapping)(object)_variableLengthBinary
			},
			{
				"int",
				(RelationalTypeMapping)(object)_int
			},
			{
				"money",
				(RelationalTypeMapping)(object)_decimal
			},
			{
				"national char varying",
				(RelationalTypeMapping)(object)_variableLengthUnicodeString
			},
			{
				"national character varying",
				(RelationalTypeMapping)(object)_variableLengthUnicodeString
			},
			{
				"national character",
				(RelationalTypeMapping)(object)_fixedLengthUnicodeString
			},
			{
				"nchar",
				(RelationalTypeMapping)(object)_fixedLengthUnicodeString
			},
			{
				"ntext",
				(RelationalTypeMapping)(object)_textAnsiString
			},
			{
				"numeric",
				(RelationalTypeMapping)(object)_decimal
			},
			{
				"double precision",
				(RelationalTypeMapping)(object)_decimal
			},
			{
				"nvarchar",
				(RelationalTypeMapping)(object)_variableLengthUnicodeString
			},
			{
				"real",
				(RelationalTypeMapping)(object)_real
			},
			{
				"rowversion",
				(RelationalTypeMapping)(object)_rowversion
			},
			{
				"smalldatetime",
				(RelationalTypeMapping)(object)_datetime
			},
			{
				"smallint",
				(RelationalTypeMapping)(object)_short
			},
			{
				"smallmoney",
				(RelationalTypeMapping)(object)_decimal
			},
			{
				"text",
				(RelationalTypeMapping)(object)_textAnsiString
			},
			{
				"clob",
				(RelationalTypeMapping)(object)_textAnsiString
			},
			{
				"interval day to second",
				(RelationalTypeMapping)(object)_intervaldt
			},
			{
				"timestamp",
				(RelationalTypeMapping)(object)_datetime
			},
			{
				"tinyint",
				(RelationalTypeMapping)(object)_sByte
			},
			{
				"char(36)",
				(RelationalTypeMapping)(object)_guid
			},
			{
				"varbinary",
				(RelationalTypeMapping)(object)_variableLengthBinary
			},
			{
				"blob",
				(RelationalTypeMapping)(object)_blobBinary
			},
			{
				"varchar",
				(RelationalTypeMapping)(object)_variableLengthAnsiString
			},
			{
				"xml",
				(RelationalTypeMapping)(object)_xml
			}
		};
		_clrTypeMappings = new Dictionary<Type, RelationalTypeMapping>
		{
			{
				typeof(int),
				(RelationalTypeMapping)(object)_int
			},
			{
				typeof(long),
				(RelationalTypeMapping)(object)_long
			},
			{
				typeof(DateTime),
				(RelationalTypeMapping)(object)_datetime2
			},
			{
				typeof(Guid),
				(RelationalTypeMapping)(object)_guid
			},
			{
				typeof(bool),
				(RelationalTypeMapping)(object)_bool
			},
			{
				typeof(sbyte),
				(RelationalTypeMapping)(object)_sByte
			},
			{
				typeof(byte),
				(RelationalTypeMapping)(object)_byte
			},
			{
				typeof(double),
				(RelationalTypeMapping)(object)_double
			},
			{
				typeof(DateTimeOffset),
				(RelationalTypeMapping)(object)_datetimeoffset
			},
			{
				typeof(short),
				(RelationalTypeMapping)(object)_short
			},
			{
				typeof(float),
				(RelationalTypeMapping)(object)_real
			},
			{
				typeof(decimal),
				(RelationalTypeMapping)(object)_decimal
			},
			{
				typeof(TimeSpan),
				(RelationalTypeMapping)(object)_intervaldt
			}
		};
		_disallowedMappings = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
		{
			"binary varying", "binary", "char varying", "char", "character varying", "character", "national char varying", "national character varying", "national character", "nchar",
			"nvarchar", "varbinary", "varchar"
		};
	}

	protected override RelationalTypeMapping FindMapping(in RelationalTypeMappingInfo mappingInfo)
	{
		RelationalTypeMapping relationalTypeMapping = this.FindRawMapping(mappingInfo);
		if (relationalTypeMapping == null)
		{
			return null;
		}
		return relationalTypeMapping.Clone( mappingInfo);
	}

	private RelationalTypeMapping FindRawMapping(RelationalTypeMappingInfo mappingInfo)
	{
		Type clrType = mappingInfo.ClrType;
		string storeTypeName = mappingInfo.StoreTypeName;
		string storeTypeNameBase = mappingInfo.StoreTypeNameBase;
		if (storeTypeName != null)
		{
			if (clrType == typeof(float) && mappingInfo.Size != null)
			{
				int? num = mappingInfo.Size;
				int num2 = 0x18;
				if (((num.GetValueOrDefault() <= num2) & (num != null)) && (storeTypeNameBase.Equals("float", StringComparison.OrdinalIgnoreCase) || storeTypeNameBase.Equals("double precision", StringComparison.OrdinalIgnoreCase)))
				{
					return this._real;
				}
			}
			RelationalTypeMapping relationalTypeMapping;
			if (this._storeTypeMappings.TryGetValue(storeTypeName, out relationalTypeMapping) || this._storeTypeMappings.TryGetValue(storeTypeNameBase, out relationalTypeMapping))
			{
				if (!(clrType == null) && !(relationalTypeMapping.ClrType == clrType))
				{
					return null;
				}
				return relationalTypeMapping;
			}
		}
		if (clrType != null)
		{
			RelationalTypeMapping relationalTypeMapping2;
			if (this._clrTypeMappings.TryGetValue(clrType, out relationalTypeMapping2))
			{
				return relationalTypeMapping2;
			}
			if (clrType == typeof(string))
			{
				bool? isUnicode = mappingInfo.IsUnicode;
				bool flag = false;
				bool flag2 = (isUnicode.GetValueOrDefault() == flag) & (isUnicode != null);
				bool valueOrDefault = mappingInfo.IsFixedLength.GetValueOrDefault();
				string text = (flag2 ? "" : "N") + (valueOrDefault ? "CHAR" : "VARCHAR2");
				int num3 = 0x7FFF;
				int num4 = (valueOrDefault ? 1 : num3);
				StoreTypePostfix? storeTypePostfix = null;
				int? num5 = new int?(mappingInfo.Size ?? (mappingInfo.IsKeyOrIndex ? (flag2 ? 0x384 : 0x1C2) : num4));
				int? num = num5;
				int num2 = num3;
				if ((num.GetValueOrDefault() > num2) & (num != null))
				{
					num5 = null;
					storeTypePostfix = StoreTypePostfix.None;
				}
				else
				{
					storeTypePostfix = StoreTypePostfix.Size;
				}
				StoreTypePostfix? storeTypePostfix2 = storeTypePostfix;
				StoreTypePostfix storeTypePostfix3 = 0;
				string text4;
				if (!((storeTypePostfix2.GetValueOrDefault() == storeTypePostfix3) & (storeTypePostfix2 != null)))
				{
					string text2 = text;
					string text3 = "(";
					num = num5;
					text4 = text2 + text3 + num.ToString() + ")";
				}
				else
				{
					text4 = "clob";
				}
				return new DmStringTypeMapping(text4, flag2 ? new DbType?(DbType.AnsiString) : null, !flag2, num5, valueOrDefault, storeTypePostfix);
			}
			if (clrType == typeof(byte[]))
			{
				if (mappingInfo.IsRowVersion.GetValueOrDefault())
				{
					return this._rowversion;
				}
				bool valueOrDefault2 = mappingInfo.IsFixedLength.GetValueOrDefault();
				string text5 = (valueOrDefault2 ? "BINARY" : "VARBINARY");
				int num6 = 0x7FFF;
				int num7 = (valueOrDefault2 ? 1 : num6);
				int? num = mappingInfo.Size;
				int? num8 = ((num != null) ? num : (mappingInfo.IsKeyOrIndex ? new int?(0x384) : new int?(num7)));
				StoreTypePostfix? storeTypePostfix4 = null;
				num = num8;
				int num2 = num6;
				if ((num.GetValueOrDefault() > num2) & (num != null))
				{
					num8 = null;
					storeTypePostfix4 = StoreTypePostfix.None;
				}
				else
				{
					storeTypePostfix4 = StoreTypePostfix.Size;
				}
				StoreTypePostfix? storeTypePostfix2 = storeTypePostfix4;
				StoreTypePostfix storeTypePostfix3 = 0;
				string text8;
				if (!((storeTypePostfix2.GetValueOrDefault() == storeTypePostfix3) & (storeTypePostfix2 != null)))
				{
					string text6 = text5;
					string text7 = "(";
					num = num8;
					text8 = text6 + text7 + num.ToString() + ")";
				}
				else
				{
					text8 = "blob";
				}
				return new DmByteArrayTypeMapping(text8, new DbType?(DbType.Binary), num8, false, null, storeTypePostfix4);
			}
		}
		return null;
	}
}
